﻿/*
Copyright (c) 2007 Eduardo G. Pons Dias da Costa

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
//*/

/**
* Class that holds all information about the tweening functions used by the Climv. It also gives the possibility to create custom functions.
* @author Eduardo Dias da Costa
* @version 0.9a
*/
class com.thelab.tween.TweenFunction 
{		
	/**
	* Container Object of all Tweening functions default and custom.
	*/
	static var _function:Object = 
	{ linear: [0,0,0,0,1],       inoutcubic:[0,0,-2,3,0],
	inoutquintic:[6,-15,10,0,0], inquintic:[1,0,0,0,0],
	outquintic:[1,-5,10,-10,5],  inquartic:[0,1,0,0,0],
	outquartic:[0,-1,4,-6,4],  	 outinquartic:[0,0,4,-6,3],
	backinquartic:[0,2,2,-3,0],	 outbackquartic:[0,-2,10,-15,8],
	incubic:[0,0,1,0,0],	     outcubic:[0,0,1,-3,3],
	outincubic:[0,0,4,-6,3], 	 backincubic:[0,0,4,-3,0],
	outbackcubic:[0,0,4,-9,6], 	 inquadratic:[0,0,0,1,0],
	outelasticsmall:[33,-106,126,-67,15], outelasticbig:[56,-175,200,-100,20],
	inelasticsmall:[33,-59,32,-5,0], inelasticbig:[56,-105,60,-10,0],	
	wvsine: Math.sin,wvcosine:Math.cos,
	wvbfsine:butterflysine,wvbfcosine:butterflycosine,
	wvcardioidsine:cardioidsine,wvcardioidcosine:cardioidcosine,
	wvstrobosine: strobosine
	};	
	
	static private var _sin:Function = Math.sin;
	static private var _cos:Function = Math.cos;
	static private var _exp:Function = Math.exp;
	static private var _round:Function = Math.round;
	static private var _ceil:Function = Math.ceil;
	static private var _floor:Function = Math.floor;
	static private var _atan:Function = Math.atan;
	static private var _atan2:Function = Math.atan2;
	
	
	/**
	* Insert a new equation into the Class. The equation will be available for later use in the Climv Class.
	* @param	name Equation name
	* @param	c5 5th order coeficient of the polynom.
	* @param	c4 4th order coeficient of the polynom.
	* @param	c3 3rd order coeficient of the polynom.
	* @param	c2 2nd order coeficient of the polynom.
	* @param	c1 1st order coeficient of the polynom.
	* @param	modifier modifirer constant that will be applied in the result. Modifier is a function that receives a number and make any kind of calculation on it before using it.
	*/
	static function addEquation(name:String,c5:Number,c4:Number,c3:Number,c2:Number,c1:Number,reverse:Boolean,modifier:Function)
	{				
		_function[name] = [(c5==undefined)?0:c5,(c4==undefined)?0:c4,(c3==undefined)?0:c3,(c2==undefined)?0:c2,(c1==undefined)?0:c1,(reverse==undefined)?false:reverse,modifier];
	}	
	
	/**
	* Insert a new custom equation for wave tweenings. Wave functions has templates like that wave(func:String,angle:Number,range:Number,offset:Number):Number
	* @param	func Function reference.
	* @param	name Name of the function.
	*/
	static function addWaveEquation(func:Function,name:String)
	{
		_function[name] = func;
	}
	
	/**
	* Receives an Array of coeficients and a value then solve the polynom.
	* @param	coef Array with 5 coeficients and 1 modifier in the end.
	* @param	value The value that will be applied in the formula.
	* @return Number - The result of the polynom.
	*/
	static function solve(coef:Array,value:Number):Number
	{		
		if(coef==undefined) return undefined;		
		var reverse:Boolean = coef[5];
		var r:Number = reverse ? 1.0 - value : value;
		var r2:Number = r*r;
		var r3:Number = r2*r;
		var r4:Number = r3*r;
		var r5:Number = r4*r;	
		var res:Number = ((coef[0]*r5)+(coef[1]*r4)+(coef[2]*r3)+(coef[3]*r2)+(coef[4]*r));
		
		if(coef[6]!=undefined) res = coef[6](res);
		return res;
	}
	
	/**
	* Receives the name of wave function an angle the result range and offset. Returns the waving value for it.
	* @param	func Wave function name.
	* @param	value Currrent angle value.
	* @param	range Maximum range of the result.
	* @param	offset Starting offset of the result. 
	* @return Number - Result.
	*/
	static function wave(angle:Number,range:Number,offset:Number,phase:Number,scale:Number,func:Function):Number
	{		
		
		return (offset+(func(angle+phase)*range))*scale;
	}
	
	/**
	* Solve the Catmull Curve between 2 points (P1 and P2) with 2 control points ( P0 and P3)
	* @param	ratio Normalized value to interpolate between the 2 points.
	* @param	p0 Control Point 1
	* @param	p1 Point 1
	* @param	p2 Point 2
	* @param	p3 Control Point 2
	* @return Object - Point with the interpolated point between P1 and P2
	*/
	static function catmull(ratio:Number,p0,p1,p2,p3,orient:Boolean):Object
	{		
		var r:Number = ratio; var r2:Number = r*r; var r3:Number = r2*r;		
		var DX:Number = (2*p1._x);
		var CX:Number = (-p0._x+p2._x);
		var BX:Number = ((2*p0._x)-(5*p1._x)+(4*p2._x)-p3._x);
		var AX:Number = (-p0._x + (3*p1._x) - (3*p2._x) + p3._x);
		var xc:Number = 0.5*(DX+(CX*r)+(BX*r2)+(AX*r3));
		var DY:Number = (2*p1._y);
		var CY:Number = (-p0._y+p2._y);
		var BY:Number = ((2*p0._y)-(5*p1._y)+(4*p2._y)-p3._y);
		var AY:Number = (-p0._y + (3*p1._y) - (3*p2._y) + p3._y);
		var yc:Number = 0.5*(DY+(CY*r)+(BY*r2)+(AY*r3));
		if(orient)
		{
			var dx:Number = 0.5*(CX+(BX*r*2)+(AX*r2*3));
			var dy:Number = 0.5*(CY+(BY*r*2)+(AY*r2*3));			
			var a:Number;
			return {x: xc,y: yc,a:-(((a=(_atan2(dy,dx)*-57.295779513082321))<0)?360+a:a)};
		}
		return {x: xc,y: yc};			
		
	}
	
	static private function butterflysine(a:Number)
	{
		var s:Function = _sin;
		var c:Function = _cos;
		var e:Function = _exp;
		var st12:Number = s(a/12);
		var s5:Number = st12*st12*st12*st12*st12;
		return s(a)*(e(c(a)) - (2*c(4*a)) - s5);
	}
	static private function butterflycosine(a:Number)
	{
		var s:Function = _sin;
		var c:Function = _cos;
		var e:Function = _exp;
		var st12:Number = s(a/12);
		var s5:Number = st12*st12*st12*st12*st12;
		return c(a)*(e(c(a)) - (2*c(4*a)) - s5);
	}
	
	static private function cardioidsine(a:Number)
	{
		var s:Function = _sin;
		var c:Function = _cos;
		return c(a)*(1.0-c(a));
	}
	static private function cardioidcosine(a:Number)
	{
		var s:Function = _sin;
		var c:Function = _cos;
		return s(a)*(1.0-c(a));
	}
	
	static private function strobosine(a:Number)
	{
		var s:Function = _sin;
		var r:Function = _floor;		
		return r(s(a));
		
	}
	
}
